#include "common.h"

void    Dump(const char* Format, ...)
    {
    va_list ArgPtr;

    if(Global::Dump())
        {
        assert(Format != NULL);
        va_start(ArgPtr, Format);
        vfprintf(stdout, Format, ArgPtr);
        va_end(ArgPtr);
        fflush(stdout);
        }
    }

void    DumpVerbose(const char* Format, ...)
    {
    va_list ArgPtr;

    if(Global::Dump() && Global::Verbose())
        {
        assert(Format != NULL);
        va_start(ArgPtr, Format);
        vfprintf(stdout, Format, ArgPtr);
        va_end(ArgPtr);
        fflush(stdout);
        }
    }



static int ErrorCode;   // connects ErrorPrologue to ErrorEpilog

/* Exit() - end-of-the-line on the way out the door.
 *
 * This is the final function called to exit blacc with an error.
 * It handles any user option indicating that a particular error code
 * and/or error on a particular line was expected, setting the exit
 * status accordingly (mainly for regression tests of blacc itself).
 *
 * Our exit status is the (non-zero) number of the error, unless
 * the user specified an expected error code/line#. In the latter
 * case, the exit status is EXIT_SUCCESS if the code/line# was
 * expected and EXIT_FAILURE otherwise.
 **********************************************************************/
void A_NORETURN    Exit(int Line, int Error)
    {
    int     Status  = -1;

    /* if command-line did not request error expectations */
    if(Global::Options.ExpectLine == -1 && Global::Options.ExpectCode == -1)
        Status      = Error;
    /* else, our status is binary: were the expectations met? */
    else
        {
        Status      = EXIT_SUCCESS;

        if(Global::Options.ExpectLine != -1 && Global::Options.ExpectLine != Line)
            Status  = EXIT_FAILURE;
        else if(Global::Options.ExpectCode != -1 && Global::Options.ExpectCode != Error)
            Status  = EXIT_FAILURE;
        }

    assert(Status != -1);

    fflush(stderr);
    fflush(stdout);
    exit(Status);
    }


/* ErrorExit() - print formatted error message and exit.
 */
void A_NORETURN ErrorExit(int Code, const char* Format, ...)
    {
    va_list ArgPtr;

    ErrorPrologue(Code);
    assert(Format != NULL);
    va_start(ArgPtr, Format);
    vfprintf(stderr, Format, ArgPtr);
    va_end(ArgPtr);
    fflush(stderr);

    Exit(-1, Code);
    }

void    ErrorPrologue(int Code)
    {
    fprintf(stderr, "blacc error %d:\n", Code);
    fflush(stderr);
    ErrorCode   = Code;
    }

void    ErrorEpilog(int Line)
    {
    Exit(Line, ErrorCode);
    }



/* Usage() - print formatted error, plus usage info, then exit.
 */
void    Usage(const char* Format, ...)
    {
    va_list ArgPtr;

    assert(Format != NULL);
    va_start(ArgPtr, Format);
    vfprintf(stderr, Format, ArgPtr);
    va_end(ArgPtr);

    fprintf(stderr, "Usage:\n");
    fprintf(stderr, "    blacc [options] file.blc\n");
    fprintf(stderr, "Where:\n");
    fprintf(stderr, "    -c###\n");
    fprintf(stderr, "        causes an exit code of 1 if an error ### is not encountered.\n");
    fprintf(stderr, "    -d\n");
    fprintf(stderr, "        dumps internal information.\n");
    fprintf(stderr, "    -fname   Display FIRST set of nonterminal 'name'.\n");
    fprintf(stderr, "    -k   emit tokenized version of input (useless to normal users).\n");
    fprintf(stderr, "    -l###\n");
    fprintf(stderr, "        causes an exit code of 1 if an error on line ### is not found.\n");
    fprintf(stderr, "    -v       Increase verbosity of output.\n");
    fprintf(stderr, "    -wname   Display FOLLOW set of nonterminal 'name'.\n");

    Exit(-1, ERROR_COMMANDLINE);
    }

